package cn.yunyichina.provider.clinic.listener;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.listener.MessageListener;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.yunyichina.provider.clinic.constant.CacheConstant;
import cn.yunyichina.provider.clinic.entity.Mzjs;
import cn.yunyichina.provider.clinic.entity.Mzzf;
import cn.yunyichina.provider.clinic.entity.TreatOrderPayJson;
import cn.yunyichina.provider.clinic.service.impl.PayServiceImpl;
import cn.yunyichina.provider.clinic.utils.DateUtils;
import cn.yunyichina.provider.framework.common.PKGenerator;
import cn.yunyichina.provider.framework.data.SpringContextHandler;
import cn.yunyichina.provider.framework.dubbo.service.BaseService;
import cn.yunyichina.provider.framework.dubbo.service.CacheService;
import cn.yunyichina.provider.iface.entity.base.OrderExceptionVo;
import cn.yunyichina.provider.iface.entity.base.OrderExtVo;
import cn.yunyichina.provider.iface.entity.common.Response;
import cn.yunyichina.utils.convert.JsonUtils;

public class ClinicAliPayMessageListener implements MessageListener<Integer, String> {

    private Logger logger = LoggerFactory.getLogger(ClinicAliPayMessageListener.class);
    @Autowired
    private PayServiceImpl payService;

    public void onMessage(ConsumerRecord<Integer, String> integerStringConsumerRecord) {
        String jsonString = integerStringConsumerRecord.value();
        logger.info("门诊支付回调, 回调入参jsonString" + jsonString);
        try {
            JSONObject jsonObject = JSON.parseObject(jsonString);
            String orderNo = (String) jsonObject.get("out_trade_no");
            String openId = (String) jsonObject.get("buyer_id");
            String appId = (String) jsonObject.get("app_id");
            String tradeNo = (String) jsonObject.get("trade_no");
            String payMode = (String) jsonObject.get("pay_mode");
            if(StringUtils.isBlank(payMode) && jsonObject.containsKey("passback_params")){
                JSONObject passback = JSON.parseObject((String) jsonObject.get("passback_params"));
                if(passback != null && passback.containsKey("pay_mode")){
                    payMode = (String) passback.get("pay_mode");
                }
            }

            Map<String, String> map = new HashMap<String, String>();
            map.put("order_no", orderNo);
            logger.info("门诊支付回调, 订单号" + orderNo + ", 调base模块, 查询订单接口入参request=" + JsonUtils.toJsonString(map));
            Response ordResponse = BaseService.callUnderlineFromInternal("yyt.base.order.by.order.no.out.get",
                    JsonUtils.toJsonString(map));
            logger.info("门诊支付回调, 订单号" + orderNo + ", 调base模块, 查询订单接口返回response=" + JSONObject.toJSONString(ordResponse));
            if (!"0".equals(ordResponse.getResultCode())) {
                logger.info("门诊支付回调, 订单号" + orderNo + ", 调base模块, 查询订单失败。");
                return;
            }
            OrderExtVo order = JsonUtils.parseObject(ordResponse.getResult(), OrderExtVo.class);

            Map<String, Object> dataMap = new HashMap<String, Object>();
            dataMap.put("yyt_order_no", orderNo);
            dataMap.put("pay_time", DateUtils.dateToString(new Date()));
            dataMap.put("user_id", openId);
            dataMap.put("payee_app_id", appId);
            
            Map<String, String> extraParamsMap = JsonUtils.parseObject(order.getExtraParams(), HashMap.class);
            if (StringUtils.isNotBlank(extraParamsMap.get("is_from_inner"))) {
                dataMap.put("is_from_inner", extraParamsMap.get("is_from_inner"));
            } else {
                dataMap.put("is_from_inner", "1");
            }
            BigDecimal totalAmount = jsonObject.getBigDecimal("total_amount");

            //门诊支付前PayMode212更改为22
            String exPayMode = payMode;
            if("212".equals(payMode)){
                payMode = "22";
            }
             
            boolean isCallbackInsurance = false;
            // 根据回调payMode判断是否医保支付
            if ("21".equals(payMode) || "22".equals(payMode) || "23".equals(payMode) || "24".equals(payMode)
                    || "25".equals(payMode) || "26".equals(payMode)) {
                // 自费支付
                isCallbackInsurance = false;
            } else if ("27".equals(payMode) || "28".equals(payMode) || "29".equals(payMode)) {
                // 医保支付
                isCallbackInsurance = true;
            } else {
                logger.info("门诊支付回调, 订单号" + order.getOrderNo() + "paymode=" + payMode + ", 未知paymode, 请联系管理员。");
                return;
            }

            if("212".equals(exPayMode)){
                order.setPayMode(Short.parseShort(exPayMode));
            }else{
                order.setPayMode(Short.parseShort(payMode));
            }

            dataMap.put("pay_mode", payMode);
            dataMap.put("ex_pay_mode", exPayMode);  //临时payMode为适应212存库逻辑
            if (order.getIsInsurance().intValue() == 0) {
                dataMap.put("pay_amount", totalAmount.multiply(new BigDecimal(100)).intValue());
            } else if (order.getIsInsurance().intValue() == 1) {
                if(isCallbackInsurance) {
                    order.setInsuranceMode((short) 1);
                String fund_bill_list = (String) jsonObject.get("fund_bill_list");
                JSONArray jsonArray = JSONObject.parseArray(fund_bill_list);
                String outsideCardFee = "";
                for (int i = 0; i < jsonArray.size(); i++) {
                    // 从回调黑盒数据中获取支付的真实意愿金额
                    JSONObject jo = jsonArray.getJSONObject(i);
                    if("OUTSIDECARD".equals(jo.getString("fundChannel"))) {
                        outsideCardFee = jo.getString("amount");
                        logger.info("门诊支付回调, 订单号" + orderNo + ", 支付回调返回医保费用outsideCardFee="+outsideCardFee);
                    }
                }

                    // 根据回调中的金额修改订单的金额
                    BigDecimal outsideCardFee_b = new BigDecimal(outsideCardFee);

                    logger.info("门诊支付回调, 订单号" + orderNo + ", 原订单自费金额payAmount=" + order.getPayAmount());
                    order.setPayAmount(totalAmount.multiply(new BigDecimal(100))
                            .subtract(outsideCardFee_b.multiply(new BigDecimal(100))).intValue());
                    order.setPayRealAmount(order.getPayAmount());
                    dataMap.put("pay_amount", order.getPayAmount());
                    logger.info("门诊支付回调, 订单号" + orderNo + ", 根据支付回调返回修改自费金额payAmount=" + order.getPayAmount());
                    logger.info("门诊支付回调, 订单号" + orderNo + ", 原订单AccountAmount=" + order.getAccountAmount());
                    //order.setAccountAmount(outsideCardFee_b.multiply(new BigDecimal(100)).intValue());
                    logger.info("门诊支付回调, 订单号" + orderNo + ", 根据支付回调返回修改AccountAmount=" + order.getAccountAmount());
                    logger.info("门诊支付回调, 订单号" + orderNo + ", 原订单InsuranceAmount=" + order.getInsuranceAmount());
                    //modify:zkw
                    order.setInsuranceRealAmount(outsideCardFee_b.multiply(new BigDecimal(100)).intValue());
                    logger.info("门诊支付回调, 订单号" + orderNo + ", 根据支付回调返回修改InsuranceAmount=" + order.getInsuranceAmount());

                    String industry_sepc_detail = (String) jsonObject.get("industry_sepc_detail");

                    String tempStr = null;
                    try {
                        // 因为支付宝传入进来的参数中含有"{、}"、"[、]"等这些字符，所以要进行替换才能进行JSON解析
                        tempStr = industry_sepc_detail.replace("\"{", "{");
                        tempStr = tempStr.replace("}\"", "}");
                        tempStr = tempStr.replace("\"[", "[");
                        tempStr = tempStr.replace("]\"", "]");
                    } catch (Exception e) {
                        addOrderToExceptionList(order, "门诊支付回调, 订单号" + orderNo + ", 解析黑盒数据出现异常");
                        logger.error("门诊支付回调, 订单号" + orderNo + ", 解析黑盒数据出现异常", e);
                    }

                    extraParamsMap.put("industry_sepc_detail", tempStr);
                    order.setExtraParams(JSON.toJSONString(extraParamsMap));
                } else {
                    dataMap.put("pay_amount", totalAmount.multiply(new BigDecimal(100)).intValue());
                }
            } else {
                logger.info("门诊支付回调, 订单号" + order.getOrderNo() + ", paymode不是22和27, 请联系管理员。");
            }

            order.setPaymentDealId(tradeNo);
            order.setIsPayHandled(1);//支付是否通知并处理0：否，1：是

            // 先保存一次订单信息，防止后续逻辑失败导致支付参数丢失。例如支付流水PaymentDealId，payMode等
            logger.info("门诊支付回调, 订单号" + order.getOrderNo() + ", 调base模块, 更新订单状态入参request="
                    + JSONObject.toJSONString(order));
            BaseService.callUnderlineFromInternal("yyt.base.order.update", JsonUtils.toJsonString(order));
            
            if(payService == null){
                payService = SpringContextHandler.getBean(PayServiceImpl.class);
            }
            Response response = payService.ackPayOrderByOrderNoOut( JsonUtils.toJsonString(dataMap),"");
            logger.info("门诊支付回调, 订单号" + order.getOrderNo() + ", 门诊写单返回response=", JSON.toJSONString(response));
            if(!"0".equals(response.getResultCode())) {
                //记录写单的异常信息
                String errMsg = response.getResultMessage();

                Map<String, String> tmpMap = new HashMap<String, String>();
                tmpMap.put("order_no", orderNo);
                logger.info("门诊支付回调, 订单号" + orderNo + ", 调base模块, 查询订单接口入参request=" + JSONObject.toJSONString(map));
                Response orderRes = BaseService.callUnderlineFromInternal("yyt.base.order.by.order.no.out.get",
                        JsonUtils.toJsonString(tmpMap));
                logger.info("门诊支付回调, 订单号" + orderNo + ", 调base模块, 查询订单接口入参response=" + JSONObject.toJSONString(orderRes));
                if (!"0".equals(orderRes.getResultCode())) {
                    logger.info("门诊支付回调, 订单号" + orderNo + ", 调base模块, 查询订单失败。");
                }
                order = JsonUtils.parseObject(orderRes.getResult(), OrderExtVo.class);
                order.setOrderStatusException();
                
                logger.info("门诊支付回调, 订单号" + order.getOrderNo() + ", 调base模块, 更新订单状态入参request="
                        + JSONObject.toJSONString(order));
                BaseService.callUnderlineFromInternal("yyt.base.order.update", JsonUtils.toJsonString(order));
                addOrderToExceptionList(order, errMsg);
            }

        } catch (Exception e) {
            logger.error("门诊支付回调, 报错", e);
        }

        logger.info("门诊支付回调结束");
    }

    private void addOrderToExceptionList(OrderExtVo vo, String errMsg) {
        logger.info("添加异常单信息, 订单号" + vo.getOrderNo() + ", 订单order=" + JSON.toJSONString(vo));
        boolean isAdd = true;
        try {
            logger.info("添加异常单信息, 订单号" + vo.getOrderNo() + ", 调用base模块, 查询是否已经存在异常单入参request=" + JSON.toJSONString(vo));
            Response response = BaseService.callUnderlineFromInternal("yyt.base.order.exception.by.order.no.get",
                    JsonUtils.toJsonString(vo));
            logger.info("添加异常单信息, 订单号" + vo.getOrderNo() + ", 调用base模块, 查询是否已经存在异常单返回response=" + JSON.toJSONString(response));
            if (!"0".equals(response.getResultCode())) {
                logger.info("添加异常单信息, 订单号" + vo.getOrderNo() + ", 调用base模块, 查询异常单信息失败");
            }

            OrderExceptionVo oe = JsonUtils.parseObject(response.getResult(), OrderExceptionVo.class);
            if (oe != null) {
                isAdd = false;
            }
        } catch (Exception e) {
            logger.info("添加异常单信息, 订单号" + vo.getOrderNo() + ", 查询异常单是否存在报错。");
        }
        
        if (isAdd) {
            OrderExceptionVo record = new OrderExceptionVo();
            record.setBranchCode(vo.getBranchCode());
            record.setBranchId(vo.getBranchId());
            record.setBranchName(vo.getBranchName());
            record.setCreatedTime(DateUtils.dateToString(new Date()));
            record.setExceptionHandlerCount(0);
            record.setRefundHandlerCount(0);
            record.setId(PKGenerator.generateId());
            record.setIsInsurance(vo.getIsInsurance());
            record.setOrderNo(vo.getOrderNo());
            record.setOrderType(vo.getOrderType());
            record.setOrgCode(vo.getOrgCode());
            record.setOrgId(vo.getOrgId());
            record.setOrgName(vo.getOrgName());
            record.setPlatformCode(vo.getPlatformCode());
            record.setPlatformId(vo.getPlatformId());
            record.setPlatformName(vo.getPlatformName());
            record.setPlatformOrgAppCode(vo.getPlatformOrgAppCode());
            record.setUpdateTime(DateUtils.dateToString(new Date()));
            record.setHandlerResult((short) 0);
            record.setHisQueryState((short) 0);
            record.setInsuranceHandlerFlag((short) 0);
            record.setSelfPayHandlerFlag((short) 0);
            //记录写单的异常信息
            record.setExceptionReason(errMsg);
            record.setExceptionClass("Clinic-ClinicAliPayMessageListener");

            logger.info("添加异常单信息, 订单号" + vo.getOrderNo() + ", 调用base模块, 添加异常单record=" + JSON.toJSONString(record));
            CacheService.setGlobalKey(CacheConstant.CACHE_CLINIC_MODULE, CacheConstant.CACHE_CLINIC_PAY_EXCEPTION_ORDER,
                    record.getOrderNo(), JSON.toJSONString(record), CacheConstant.CACHE_NOT_EXPIRETIME);

            BaseService.callUnderlineFromInternal("", "yyt.base.order.exception.add", JsonUtils.toJsonString(record));
        }
        logger.info("添加异常单信息, 订单号" + vo.getOrderNo() + ", 结束");
    }
}
